/**
 * note:联合类型的分布式特性（触发条件：条件类型、联合类型+泛型）
 * 1. 通过泛型参数传入
 * 2.泛型参数不能被包裹，包裹后将不会再进行分发
 */

// 分布式条件类型
// 1.
// type Type1<T> = string extends T ? "A" : "B"; // 等价于string extends T ? "A" : "B"
// // 2.
// type Type2<T> = string | number extends T ? "A" : "B"; // 等价于 string extends T ? 'a' : 'b'; number extends T ? "A" : "B"

// type MyPick<T, K extends keyof T> = {
//   [P in K]: T[P];
// };

// type MyOmit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;

// interface Todo {
//   title: string;
//   description: string;
//   completed: boolean;
// }
// type TodoPreview = MyPick<Todo, "title" | "completed">;
// type TodoPreview2 = MyOmit<Todo, "title" | "completed">;

// 选取部分属性，做一个可选操作
type User = {
  id?: number;
  name: string;
  age: number;
  tel: string;
  address: string;
};
// 将部分键名设置为可选。
// type RequiredPick = Required<Omit<User, "age" | "tel" | "address">>;
// type PartialPick = Partial<Pick<User, "age" | "tel" | "address">>;
// type OptionalPick = RequiredPick & PartialPick;
type OptionalPick2<T, K extends keyof T> = Required<Omit<T, K>> &
  Partial<Pick<T, K>>;

const user2: OptionalPick2<User, "age" | "address" | "tel"> = {
  id: 1,
  name: "22",
};

// 分布式特性 泛型不能被包裹
type ABB<T> = T extends any ? T[] : never;
type ACC<T> = [T] extends any ? T[] : never;

type F = ABB<string | number>; // string[] | number[]
type E = ACC<string | number>; // (string | number)[]

// 避免分布式：
export type NoDistribute<T> = T & {};
type Wrapped<T> = T[] extends boolean[] ? "Y" : "N";
type Res1 = Wrapped<any>; // N
type Intersection<A, B> = A extends B ? A : never;
type IntersectionRes = Intersection<1 | 2 | 3, 2 | 3 | 4>; // 2 | 3

type MyPick<T, K extends keyof T> = {
  [Key in K]: T[Key];
};
type qweqwe = { name: string; age: number; address: string };
type MyPickRes = MyPick<qweqwe, "name" | "age"> & {};

type MyOmit<T, K extends keyof T> = {
  [Key in Exclude<keyof T, K>]: T[Key];
};

type Swap<T extends any[]> = T extends [infer A, ...infer R, infer B]
  ? [B, ...R, A]
  : T;
type SwapRes = Swap<[1, 2, 3, 4, 5]>; // [5, 2, 3, 4, 1]

type GetReturnType<T extends new (...args: any[]) => any> = T extends new (
  ...args: any[]
) => infer R
  ? R
  : never;

type GetReturnTypeRes = GetReturnType<new () => string>; // string
